﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Pavilion.DesignerTool
{
    public class FrameData
    {
        public Frame Frame { get; set; }
        public NotifiableCollection<TextureData> TextureDataCollection { get; private set; }
        public UndoRedoController UndoRedoController { get; private set; }

        private List<CTexture2D> OriginalTextureList { get; set; }

        public FrameData(Frame frame)
        {
            this.Frame = frame;
            TextureDataCollection = new NotifiableCollection<TextureData>();

            for (int i = 0; i < this.Frame.TextureList.Count; i++)
                TextureDataCollection.Add(new TextureData(this.Frame.TextureList[i], i.ToString()) { DisplayName = "Layer " + i.ToString() });

            UndoRedoController = new UndoRedoCollection<TextureData>(TextureDataCollection);
            OriginalTextureList = new List<CTexture2D>(Frame.TextureList);

            TextureDataCollection.Added += (TextureData textureData, int index) => 
            {
                if (textureData.DisplayName == null)
                    textureData.DisplayName = ObtainUniqueNameFromCollection();
                this.Frame.TextureList.Insert(index, textureData.Texture); 
            };
            TextureDataCollection.Removed += (TextureData textureData, int index) => { this.Frame.TextureList.RemoveAt(index); };
            TextureDataCollection.Moved += (int oldIndex, int newIndex) => { this.Frame.TextureList.Move(oldIndex, newIndex); };
        }

        public TextureData CreateNewTexture()
        {
            int width = Frame.Width;
            int height = Frame.Height;

            if (width == 0)
                width = 300;
            if (height == 0)
                height = 300;

            return new TextureData(new CTexture2D(CTexture2D.CreateTexture(width, height)), null);
        }

        public void Save(string fullFramePath)
        {
            PrepareFrameForSaving(fullFramePath);

            int count = 0;
            foreach (TextureData textureData in TextureDataCollection)
                textureData.Save(fullFramePath + @"\", "" + count++);
        }

        private void PrepareFrameForSaving(string fullFramePath)
        {
            DeleteAllRemovedTextures(fullFramePath);
            DeleteAllDifferentIndexTextures(fullFramePath);
            CreateFrameFolders(fullFramePath);

            ResetSaveTrackingPoint();
        }

        private void ResetSaveTrackingPoint()
        {
            OriginalTextureList.Clear();
            if (Frame.TextureList.Count > 0)
                OriginalTextureList.AddRange(Frame.TextureList);

            Frame.EnableLoading = true;
        }

        private static void CreateFrameFolders(string fullFramePath)
        {
            if (!Directory.Exists(fullFramePath + @"\"))
                Directory.CreateDirectory(fullFramePath + @"\");
        }

        private void DeleteAllDifferentIndexTextures(string fullFramePath)
        {
            for (int i = 0; i < Frame.TextureList.Count; i++)
            {
                if (IsTextureDifferentIndex(i) && !IsTextureNew(i))
                    File.Delete(fullFramePath + @"\" + OriginalTextureList.IndexOf(Frame.TextureList[i]).ToString() + ".png");
            }
        }

        private void DeleteAllRemovedTextures(string fullFramePath)
        {
            foreach (CTexture2D texture in OriginalTextureList)
            {
                if (!Frame.TextureList.Contains(texture))
                    File.Delete(fullFramePath + @"\" + OriginalTextureList.IndexOf(texture).ToString() + ".png");
            }
        }

        private bool IsTextureDifferentIndex(int textureIndex) { return textureIndex >= OriginalTextureList.Count || Frame.TextureList[textureIndex] != OriginalTextureList[textureIndex]; }

        private bool IsTextureNew(int textureIndex) { return !OriginalTextureList.Contains(Frame.TextureList[textureIndex]); }

        private string ObtainUniqueNameFromCollection()
        {
            int count = 0;

            while (true)
            {
                string name = "Layer " + count.ToString();
                if (IsNameUniqueInCollection(name))
                    return name;
                else
                    count++;
            }
        }

        private bool IsNameUniqueInCollection(string name)
        {
            foreach (TextureData textureData in TextureDataCollection)
            {
                if (textureData.DisplayName == name)
                    return false;
            }

            return true;
        }
    }
}
